Thinking in java 学习笔记(1)之对象与static关键字

句柄

1
String s = "abcd";

String s 中s为句柄,通过=连接对象”abcd”.最终通过句柄来操作对象

内存中数据保存的位置

  1. 寄存器

    这是最快的保存区域,因为它位于和其他所有保存方式不同的地方:处理器内部。然而,寄存 器的数量十分有限,所以寄存器是根据需要由编译器分配。我们对此没有直接的控制权,也不可能在自己的 程序里找到寄存器存在的任何踪迹。
  2. 堆栈

    驻留于常规 RAM(随机访问存储器)区域,但可通过它的“堆栈指针”获得处理的直接支持。堆 栈指针若向下移,会创建新的内存;若向上移,则会释放那些内存。这是一种特别快、特别有效的数据保存 方式,仅次于寄存器。创建程序时,Java 编译器必须准确地知道堆栈内保存的所有数据的“长度”以及“存 在时间”。这是由于它必须生成相应的代码,以便向上和向下移动指针。这一限制无疑影响了程序的灵活 性,所以尽管有些 Java 数据要保存在堆栈里——特别是对象句柄,但Java 对象并不放到其中。


  3. 一种常规用途的内存池(也在 RAM区域),其中保存了Java 对象。和堆栈不同,“内存堆”或 “堆”(Heap)最吸引人的地方在于编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要 在堆里停留多长的时间。因此,用堆保存数据时会得到更大的灵活性。要求创建一个对象时,只需用new命 令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存。当然,为达到这种灵活性,必然 会付出一定的代价:在堆里分配存储空间时会花掉更长的时间!
  4. 静态存储

    这儿的“静态”(Static)是指“位于固定位置”(尽管也在 RAM里)。程序运行期间,静 态存储的数据将随时等候调用。可用static 关键字指出一个对象的特定元素是静态的。但 Java 对象本身永 远都不会置入静态存储空间。
  5. 常数存储

    常数值通常直接置于程序代码内部。这样做是安全的,因为它们永远都不会改变。有的常数 需要严格地保护,所以可考虑将它们置入只读存储器(ROM)。
  6. 非RAM 存储

    若数据完全独立于一个程序之外,则程序不运行时仍可存在,并在程序的控制范围之外。 其中两个最主要的例子便是“流式对象”和“固定对象”。对于流式对象,对象会变成字节流,通常会发给 另一台机器。而对于固定对象,对象保存在磁盘中。即使程序中止运行,它们仍可保持自己的状态不变。对 于这些类型的数据存储,一个特别有用的技巧就是它们能存在于其他媒体中。一旦需要,甚至能将它们恢复 成普通的、基于RAM的对象。

主要类型

类型 大小 默认值 最小值 最大值 封装器类型
boolean 1位 false - - Boolean
char 16位 ‘\u0000’(null) Unicode 0 Unicode 2^16-1 Character
byte 8位 (byte)0 -128 +127 Byte
short 16位 (short)0 -2^15 +2^15-1 Short
int 32位 0 -2^31 -2^31-1 integer
long 64位 0L +2^63 +2^63-1 Long
float 32位 0.0f IEEE754 IEEE754 Float
double 64位 0.0d IEEE754 IEEE754 Double
void - - - - Void

static关键词

一种情形是只想用一个存储区域来保存一个特定的数据——无论要创建多少个对象,甚至根本不创建对象。另一种情形是我们需要一个特殊的方法,它没有与这个类的任何对象关联。也就是说,即使没有创建对象,也需要一个能调用的方法。为满足这两方面的要求,可使用static(静态)关键字。一旦将什么东西设为static,数据或方法就不会同那个类的任何对象实例联系到一起。

  • 由于static方法不需要创建任何对象,所以它们不可简单地调用其他那些成员,同时不引用一个已命名的对象,从而直接访问非static成员或方法(因为非static成员和方法必须同一个特定的对象关联到一起)。

    构造器初始化顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Window{
Window(int marker){
print("Window("+marker+")");
}
}

class House{
Window w1 = new Window(1);
House() {
print("House()");
w3 = new Window(33);
}
Window w2 = new Window(2);
void f(){
print("f()");
}
Window w3 = new Window(3);
}

public class OrderOfinitialization{
public static void main(String[] args){
House h = new house(0);
h.f();
}
}

"输出"
Window(1)
Window(2)
Window(3)
House()
Window(33)

静态数据的初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class Bowl {
Bowl(int marked){
System.out.println("Bowl("+marked+")");
}
void f1(int marked){
System.out.println("f1("+marked+")");
}
}

public class Table {
static Bowl bowl1 = new Bowl(1);
Table() {
System.out.println("Table()");
bowl2.f1(1);
}
void f2(int marker){
System.out.println("f2("+marker+")");
}
static Bowl bowl2 = new Bowl(2);
}

public class Cupboard {
Bowl bowl3 = new Bowl(3);
static Bowl bowl4 = new Bowl(4);
Cupboard(){
System.out.println("Cupboard()");
bowl4.f1(2);
}
void f3(int marker){
System.out.println("f3("+marker+")");
}
static Bowl bowl5 = new Bowl(5);
}

public class StaticInitialization {
public static void main(String[] args){
System.out.println("Creating new Cupboard() in main");
new Cupboard();
System.out.println("Creating new Cupboard() in main2 ");
new Cupboard();
table.f2(1);
cupboard.f3(1);
}
static Table table = new Table();
static Cupboard cupboard = new Cupboard();
}

"程序输出结果"
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main2
Bowl(3)
Cupboard()
f1(2)
f2(1)
f3(1)
规律
  • 静态初始化只有在有必要的时候才会进行(创建对象或者访问静态数据成员)
  • 初始化的顺序是先静态对象后非静态对象
  • 静态块等同于其他静态类型(如对象方法等)